#include "ArrayList.h"


template <class E>
ostream& operator<< (ostream& s, ArrayList<E>& list){
	if (list.size == 0){
		s << "[]";
		return s;
	}

	s << '['<<list[0];
	for (int i = 1; i < list.size; ++i)
		s << ',' << list[i];
	s << ']';
	return s;
}

template <class E>
E* ArrayList<E>::getArray() const {
	return arrayPointer;
}

template <class E>
int ArrayList<E>::getSize() const {
	return size;
}

template <class E> 
ArrayList<E>::ArrayList()
{
	if (arrayPointer != NULL) delete[] arrayPointer;
	arrayPointer = NULL;

	size = 0;
	capacity = DEFAULT_CAPACITY;
	arrayPointer = new E[DEFAULT_CAPACITY];
	if (arrayPointer == NULL) throw IndexOutOfBoundsException();
	capacity = DEFAULT_CAPACITY;
}

template <class E>
ArrayList<E>::ArrayList(const int& newCapacity) 
{
	if (newCapacity < 1) throw IndexOutOfBoundsException();

	size = 0;
	capacity = 0;
	arrayPointer = new E[newCapacity];
	if (arrayPointer == NULL) throw IndexOutOfBoundsException();
	capacity = newCapacity;
	
}

template<class E>
ArrayList<E>::~ArrayList()
{
	if (arrayPointer != NULL) delete[] arrayPointer;
}

template <class E>
void ArrayList<E>::add(const E& e)
{
	if (size + 1 > capacity){
		E* tempPointer = new E[capacity * 2];
		if (tempPointer == NULL) throw IndexOutOfBoundsException();

		for (int i = 0; i < size; ++i)
			tempPointer[i] = arrayPointer[i];

		if (arrayPointer != NULL) delete[] arrayPointer;
		arrayPointer = tempPointer;

		capacity *= 2;
		cout << "Doubled the array capacity." << endl;
	}
	
	arrayPointer[size++] = e;
}

template <class E>
void ArrayList<E>::add(const E& e, const int& index)
{
	if (index > size) throw IndexOutOfBoundsException();

	if (size + 1 > capacity){
		E* tempPointer = new E[capacity * 2];
		if (tempPointer == NULL) throw IndexOutOfBoundsException();

		for (int i = 0; i < size; ++i)
			tempPointer[i] = arrayPointer[i];

		if (arrayPointer != NULL) delete[] arrayPointer;
		arrayPointer = tempPointer;

		capacity *= 2;
		cout << "Doubled the array capacity." << endl;
	}

	
	for (int i = ++size-1; i > index; --i)
		arrayPointer[i] = arrayPointer[i-1];

	arrayPointer[index] = e;

}


template <class E>
void ArrayList<E>::remove(const int& index)
{
	if (index < 0 || index > size - 1) return; //throw error

	for (int i = index; i < size - 1; ++i)
		arrayPointer[i] = arrayPointer[i+1];

	if (--size < capacity / 2){
		E* tempPointer = new E[capacity / 2];
		if (tempPointer == NULL) throw IndexOutOfBoundsException();

		for (int i = 0; i < size; ++i)
			tempPointer[i] = arrayPointer[i];

		if (arrayPointer != NULL) delete[] arrayPointer;
		arrayPointer = tempPointer;

		capacity /= 2;
		cout << "Halved the array capacity." << endl;
	}
}

template <class E>
E& ArrayList<E>::operator[] (const int& i){
	if (i < 0 || i > size - 1); //throw error
	return arrayPointer[i];
}




